﻿//==============================================================================
// File: TabMenuDockManager.cs
// Created: 2010-05-28
// Author: Piotr Włodek, Arek Świerczek
//==============================================================================
// This file is a part of MAMMOTH project.
// Copyright (C) 2010 AGH University of Science and Technology, Krakow.
// https://caribou.iisg.agh.edu.pl/trac/mammoth
//
// Mammoth is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// Mammoth is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with Mammoth. If not, see http://www.gnu.org/licenses/.
//==============================================================================

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;

namespace WpfRcp.Controls
{
    public abstract class TabMenuDockManager
    {
        private int m_Counter;
        private readonly Dictionary<int, TabMenuItemWindow> m_SingletonWindows = new Dictionary<int, TabMenuItemWindow>();

        public static object GetDock(DependencyObject obj)
        {
            return obj.GetValue(DockProperty);
        }

        public static void SetDock(DependencyObject obj, object value)
        {
            obj.SetValue(DockProperty, value);
        }

        public static readonly DependencyProperty DockProperty =
            DependencyProperty.RegisterAttached("Dock", typeof(object), typeof(TabMenuDockManager), new UIPropertyMetadata(null));

        public static int GetSingletonIndex(DependencyObject obj)
        {
            return (int)obj.GetValue(SingletonIndexProperty);
        }

        public static void SetSingletonIndex(DependencyObject obj, int value)
        {
            obj.SetValue(SingletonIndexProperty, value);
        }

        public static readonly DependencyProperty SingletonIndexProperty =
            DependencyProperty.RegisterAttached("SingletonIndex", typeof(int), typeof(TabMenuDockManager), new UIPropertyMetadata(0));

        public void RegisterWindow(TabMenuItemWindow window)
        {
            window.Attach += OnWindowAttach;
            window.ContentClose += OnWindowContentClose;
        }

        public void RegisterSingletonWindow(TabMenuItemWindow window, string regionName)
        {
            var obj = GetDock(window);
            if (obj == null)
            {
                SetDock(window, regionName);

                m_Counter++;
                m_SingletonWindows.Add(m_Counter, window);
                SetSingletonIndex(window, m_Counter);
                window.Attach += OnWindowAttach;
                window.ContentClose += OnWindowContentClose;
            }
        }

        public void RegisterItem(ITabMenuItem item, string regionName)
        {
            var obj = GetDock(item as DependencyObject);
            if (obj == null)
            {
                SetDock(item as DependencyObject, regionName);

                item.Detach += OnContentUndock;
                item.Close += OnContentClose;
            }
        }

        private void OnContentClose(object sender, RoutedEventArgs e)
        {
            var tabMenuItem = (TabMenuItem)sender;
            int index = GetSingletonIndex(tabMenuItem);
            object content = null;
            if (index > 0)
            {
                var window = m_SingletonWindows[index];
                content = tabMenuItem.Content;
                tabMenuItem.Content = null;

                window.Margin = tabMenuItem.DetachedMargin;
                window.Content = content;
            }

            OnContentClose(tabMenuItem, content);
        }

        private void OnWindowContentClose(object sender, RoutedEventArgs e)
        {
            var element = (TabMenuItemWindow) sender;
            OnContentClose(element, element.Content);
        }

        private void OnWindowAttach(object sender, RoutedEventArgs e)
        {
            var window = (TabMenuItemWindow) sender;
            var menuItem = window.MenuItem;

            SetSingletonIndex(menuItem, GetSingletonIndex(window));

            object content = window.Content;
            window.Content = null;
            menuItem.Content = content;

            window.Close();

            OnContentDock(window, menuItem);
        }

        private void OnContentUndock(object sender, RoutedEventArgs e)
        {
            var args = (DetachRoutedEventArgs) e;
            var tabMenuItem = (TabMenuItem) sender;
            TabMenu tabControl = args.ParentTabMenu;

            if (tabControl != null)
            {
                Rect bounds = GetElementBounds(tabControl);

                TabMenuItemWindow window;
                int index = GetSingletonIndex(tabMenuItem);
                if (index > 0)
                    window = m_SingletonWindows[index];
                else
                {
                    window = new TabMenuItemWindow(tabControl, tabMenuItem);
                    window.SetResourceReference(FrameworkElement.StyleProperty, TabMenuItem.DetachedTabMenuItemWindowStyleKey);
                    window.Height = bounds.Height;
                    window.Width = bounds.Width;
                    window.Owner = Application.Current.MainWindow;
                    window.ShowInTaskbar = false;
                }

                OnContentUndock(window, tabMenuItem);

                object content = tabMenuItem.Content;
                tabMenuItem.Content = null;

                window.Margin = tabMenuItem.DetachedMargin;
                window.Content = content;
                window.Show();
            }
        }

        protected static Rect GetElementBounds(FrameworkElement element)
        {
            var left = Canvas.GetLeft(element);
            if (double.IsNaN(left)) left = 0.0;

            var top = Canvas.GetTop(element);
            if (double.IsNaN(top)) top = 0.0;

            var width = element.Width;
            if (double.IsNaN(width)) width = element.ActualWidth;

            var height = element.Height;
            if (double.IsNaN(height)) height = element.ActualHeight;

            return new Rect(left, top, width, height);
        }

        protected abstract void OnContentDock(TabMenuItemWindow window, TabMenuItem item);
        protected abstract void OnContentUndock(TabMenuItemWindow window, TabMenuItem item);
        protected abstract void OnContentClose(TabMenuItem item, object content);
        protected abstract void OnContentClose(TabMenuItemWindow window, object content);
    }
}